package square;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;

/**
 * A testclass for the class Square.
 * 
 * @version	1.0
 * @author	Dries Liebens 
 * 			Loic Vercruysse
 */

public class SquareTest {

	@Before
	public void setUp() throws Exception {
		square = new Square();
	}

	private static Square square;

	@Test
	public final void defaultConstructor() {
		Square newSquare = new Square();
		assertEquals(0,Double.compare(20,newSquare.getTemperature(Temperature.CELCIUS)));
		assertEquals(0,Double.compare(0,newSquare.getHumidity()));
	}
	
	@Test
	public final void extendedConstructor_noError() {
		Square newSquare = new Square(50, Temperature.CELCIUS, 20);
		assertEquals(0, Double.compare(50,newSquare.getTemperature(Temperature.CELCIUS)));
		assertEquals(0, Double.compare(20,newSquare.getHumidity()));
	}
		
	@Test (expected=IllegalArgumentException.class)
	public final void extendedConstructor_toLowTemperature_exception() {
		new Square(-201, Temperature.CELCIUS,101);
	}
	
	@Test (expected=IllegalArgumentException.class)
	public final void extendedConstructor_toHighTemperature_exception() {
		new Square(5001, Temperature.CELCIUS,101);
	}
	
	@Test
	public final void extendedConstructor_maximumTemperatureBorder() {
		new Square(5000, Temperature.CELCIUS,101);
	}
	
	@Test
	public final void extendedConstructor_minimumTemperatureBorder() {
		new Square(-200, Temperature.CELCIUS,101);
	}
	
	@Test
	public final void isValidTemperatureScale() {
		assertTrue(Square.isValidTemperatureScale(Temperature.CELCIUS));
		assertTrue(Square.isValidTemperatureScale(Temperature.FAHRENHEIT));
		assertTrue(Square.isValidTemperatureScale(Temperature.KELVIN));
	}
	
	@Test
	public final void setTemperature_legalCase() {
		square.setTemperature(5000, Temperature.CELCIUS);
		assertEquals(0, Double.compare(5000, square.getTemperature(Temperature.CELCIUS)));
		square.setTemperature(-200, Temperature.CELCIUS);
		assertEquals(0, Double.compare(-200, square.getTemperature(Temperature.CELCIUS)));
		
		square.setTemperature(5273.15, Temperature.KELVIN);
		assertEquals(0, Double.compare(5000,square.getTemperature(Temperature.CELCIUS)));
		square.setTemperature(74, Temperature.KELVIN);
		assertEquals(0, Double.compare(74, square.getTemperature(Temperature.KELVIN)));
	}
	
	@Test (expected=IllegalArgumentException.class)
	public final void setTemperature_toLow_illegalCase() {
		square.setTemperature(-201, Temperature.CELCIUS);
	}
	
	@Test (expected=IllegalArgumentException.class)
	public final void setTemperature_toHigh_illegalCase() {
		square.setTemperature(5001, Temperature.CELCIUS);
	}
	
	@Test
	public final void canHaveAsTemperature() {
		assertTrue(square.canHaveAsTemperature(-200,Temperature.CELCIUS));
		assertTrue(square.canHaveAsTemperature(5000,Temperature.CELCIUS));
		assertTrue(square.canHaveAsTemperature(251,Temperature.CELCIUS));
		assertFalse(square.canHaveAsTemperature(-201,Temperature.CELCIUS));
		assertFalse(square.canHaveAsTemperature(5001,Temperature.CELCIUS));
	}
	
	@Test
	public final void setMaximumTemperature_legalCase() {
		square.setMaximumTemperature(20, Temperature.CELCIUS);
		square.setMaximumTemperature(50, Temperature.CELCIUS);
	}
	
	@Test (expected=IllegalArgumentException.class)
	public final void setMaximumTemperature_illegalCase() {
		square.setMaximumTemperature(19, Temperature.CELCIUS);
	}
	
	@Test
	public final void setMinimumTemperature_legalCase() {
		square.setMinimumTemperature(19, Temperature.CELCIUS);
		square.setMinimumTemperature(20, Temperature.CELCIUS);
	}
	
	@Test (expected=IllegalArgumentException.class)
	public final void setMinimumTemperature_illegalCase() {
		square.setMinimumTemperature(21, Temperature.CELCIUS);
	}
	
	@Test
	public final void canHaveAsMaximumTemperature() {
		square.setTemperature(-200, Temperature.CELCIUS);
		assertTrue(square.canHaveAsMaximumTemperature(10,Temperature.CELCIUS));
		assertTrue(square.canHaveAsMaximumTemperature(-200,Temperature.CELCIUS));
		assertFalse(square.canHaveAsMaximumTemperature(-201,Temperature.CELCIUS));
	}
	
	@Test
	public final void canHaveAsMinimumTemperature() {
		square.setTemperature(5000, Temperature.CELCIUS);
		assertTrue(square.canHaveAsMinimumTemperature(20, Temperature.CELCIUS));
		assertTrue(square.canHaveAsMinimumTemperature(5000, Temperature.CELCIUS));
		assertFalse(square.canHaveAsMinimumTemperature(5001, Temperature.CELCIUS));
	}
	
	@Test
	public final void setHumidity() {
		square.setHumidity(0);
		assertEquals(0,Double.compare(0, square.getHumidity()));
		square.setHumidity(50);
		assertEquals(0,Double.compare(50, square.getHumidity()));
		square.setHumidity(100);
		assertEquals(0,Double.compare(100, square.getHumidity()));
	}
	
	@Test
	public final void isValidHumidity() {
		assertTrue(Square.isValidHumidity(0));
		assertTrue(Square.isValidHumidity(100));
		assertTrue(Square.isValidHumidity(50));
		assertFalse(Square.isValidHumidity(101));
		assertFalse(Square.isValidHumidity(-1));
	}
	
	@Test
	public final void rustDamage(){
		square.setHumidity(30);	
		assertEquals(0, square.calculateRustDamage());
		square.setHumidity(31);
		assertEquals(0, Double.compare(1/7, 1/7));
	}
	
	@Test
	public final void setThresholdHeatDamageTemperature_legalCase(){
		Square.setThresholdHeatDamageTemperature(50, Temperature.CELCIUS);
		assertEquals(0,Double.compare(50,Square.getThresholdHeatDamageTemperature(Temperature.CELCIUS)));
	}
	
	@Test (expected=IllegalArgumentException.class)
	public final void setThresholdHeatDamageTemperature_illegalCase() {
		Square.setThresholdHeatDamageTemperature(-10, Temperature.CELCIUS);
	}
	
	@Test
	public final void isValidThresholdHeatDamageTemperature() {
		assertTrue(Square.isValidThresholdHeatDamageTemperature(
				Square.getThresholdColdDamageTemperature(Temperature.CELCIUS)+1,Temperature.CELCIUS));
		assertFalse(Square.isValidThresholdHeatDamageTemperature(
				Square.getThresholdColdDamageTemperature(Temperature.CELCIUS)-1,Temperature.CELCIUS));
		assertFalse(Square.isValidThresholdHeatDamageTemperature(
				Square.getThresholdColdDamageTemperature(Temperature.CELCIUS),Temperature.CELCIUS));
	}
	
	@Test
	public final void isValidIncrementSizeHeatDamage() {
		assertFalse(Square.isValidIncrementSizeHeatDamage(-1));
		assertFalse(Square.isValidIncrementSizeHeatDamage(0));
		assertTrue(Square.isValidIncrementSizeHeatDamage(50));
	}	
	
	@Test 
	public final void setIncrementSizeHeatDamage_legalCase() {
		Square.setIncrementSizeHeatDamage(32.6, Temperature.CELCIUS);
		assertEquals(0,Double.compare(32.6,Square.getIncrementSizeHeatDamage(Temperature.CELCIUS)));
	}
	
	@Test (expected=IllegalArgumentException.class)
	public final void setIncrementSizeHeatDamage_illegalCase() {
		Square.setIncrementSizeHeatDamage(0, Temperature.CELCIUS);
	}
		
	@Test
	public final void calculateHeatDamage(){
		square.setTemperature(30, Temperature.CELCIUS);
		assertEquals(0, square.calculateHeatDamage() );	

		square.setTemperature(35, Temperature.CELCIUS);
		assertEquals(0, square.calculateHeatDamage());
		
		square.setTemperature(Temperature.CELCIUS.convertTo(51, Temperature.FAHRENHEIT), Temperature.FAHRENHEIT);
		assertEquals(1, square.calculateHeatDamage());
		
		square.setTemperature(Temperature.CELCIUS.convertTo(66, Temperature.KELVIN),Temperature.KELVIN);
		assertEquals(2, square.calculateHeatDamage());
	
	}
	
	@Test
	public final void calculateColdDamage(){
		square.setTemperature(30, Temperature.CELCIUS);
		assertEquals(0, square.calculateColdDamage() );	

		square.setTemperature(-6, Temperature.CELCIUS);
		assertEquals(1, square.calculateColdDamage());
		
		square.setTemperature(Temperature.CELCIUS.convertTo(-6, Temperature.FAHRENHEIT), Temperature.FAHRENHEIT);
		assertEquals(1, square.calculateColdDamage());
		
		square.setTemperature(Temperature.CELCIUS.convertTo(-16, Temperature.KELVIN),Temperature.KELVIN);
		assertEquals(2, square.calculateColdDamage());
	}
	
	@Test
	public final void setMadeOfSlipperyMaterial(){
		square.setMadeOfSlipperyMaterial(true);
		assertEquals(true, square.isMadeOfSlipperyMaterial());
		
		square.setMadeOfSlipperyMaterial(false);
		assertEquals(false, square.isMadeOfSlipperyMaterial());
		
	}
	
	@Test
	public final void isSlippery(){
		square.setMadeOfSlipperyMaterial(false);
		square.setTemperature(0, Temperature.CELCIUS);
		square.setHumidity(0);
		assertFalse(square.isSlippery());
		
		square.setMadeOfSlipperyMaterial(true);
		square.setTemperature(0, Temperature.CELCIUS);
		square.setHumidity(0);
		assertTrue(square.isSlippery());
		
		square.setMadeOfSlipperyMaterial(false);
		square.setTemperature(1, Temperature.CELCIUS);
		square.setHumidity(99);
		assertFalse(square.isSlippery());
		
		square.setMadeOfSlipperyMaterial(false);
		square.setTemperature(1, Temperature.CELCIUS);
		square.setHumidity(100);
		assertTrue(square.isSlippery());
		
		square.setMadeOfSlipperyMaterial(false);
		square.setTemperature(-1, Temperature.CELCIUS);
		square.setHumidity(10);
		assertFalse(square.isSlippery());
		
		square.setMadeOfSlipperyMaterial(false);
		square.setTemperature(-1, Temperature.CELCIUS);
		square.setHumidity(11);
		assertTrue(square.isSlippery());
	}
	
	@Test
	public final void calculateInhabitability() {
		square.setTemperature(100, Temperature.CELCIUS);
		square.setHumidity(100);
		assertEquals(0,Double.compare(-8,square.calculateInhabitability()));
	}
	
	@Test
	public final void addBorders_addAll() {
		square.addBorders(Direction.ONE, Direction.TWO, Direction.THREE,
							Direction.FOUR, Direction.FIVE, Direction.SIX);
		assertTrue(square.hasBorder(Direction.ONE));
		assertTrue(square.hasBorder(Direction.TWO));
		assertTrue(square.hasBorder(Direction.THREE));
		assertTrue(square.hasBorder(Direction.FOUR));
		assertTrue(square.hasBorder(Direction.FIVE));
		assertTrue(square.hasBorder(Direction.SIX));
	}
	
	@Test
	public final void addBorders_addOne(){
		square.addBorders(Direction.ONE);
		assertTrue(square.hasBorder(Direction.ONE));
		assertFalse(square.hasBorder(Direction.TWO));
		assertFalse(square.hasBorder(Direction.THREE));
		assertFalse(square.hasBorder(Direction.FOUR));
		assertFalse(square.hasBorder(Direction.FIVE));
		assertFalse(square.hasBorder(Direction.SIX));
	}
	
	@Test
	public final void addBorders_sameBorders() {
		square.addBorders(Direction.ONE);
		square.addBorders(Direction.ONE);
		assertTrue(square.hasBorder(Direction.ONE));
		assertFalse(square.hasBorder(Direction.TWO));
		assertFalse(square.hasBorder(Direction.THREE));
		assertFalse(square.hasBorder(Direction.FOUR));
		assertFalse(square.hasBorder(Direction.FIVE));
		assertFalse(square.hasBorder(Direction.SIX));
	}
	
	@Test
	public final void removeBorders() {
		square.addBorders(Direction.ONE);
		assertTrue(square.hasBorder(Direction.ONE));
		square.removeBorder(Direction.ONE);
		assertFalse(square.hasBorder(Direction.ONE));
		
		square.removeBorder(Direction.ONE);
		assertFalse(square.hasBorder(Direction.ONE));
	}
	
	@Test
	public final void removeAllBorders() {
		square.addBorders(Direction.ONE, Direction.TWO, Direction.THREE,
				Direction.FOUR, Direction.FIVE, Direction.SIX);
		
		square.removeAllBorders();
		
		assertFalse(square.hasBorder(Direction.ONE));
		assertFalse(square.hasBorder(Direction.TWO));
		assertFalse(square.hasBorder(Direction.THREE));
		assertFalse(square.hasBorder(Direction.FOUR));
		assertFalse(square.hasBorder(Direction.FIVE));
		assertFalse(square.hasBorder(Direction.SIX));
	}

	@Test
	public final void hasBorders() {
		square.addBorders(Direction.ONE);
		assertTrue(square.hasBorder(Direction.ONE));
		assertFalse(square.hasBorder(Direction.TWO));
	}
	
	@Test
	public final void isValidConstantForWeightedAverageOfTemperature() {
		assertTrue(Square.isValidConstantForWeightedAverageOfTemperature(0.1));
		assertTrue(Square.isValidConstantForWeightedAverageOfTemperature(0.4));
		assertTrue(Square.isValidConstantForWeightedAverageOfTemperature(0.20));
		
		assertFalse(Square.isValidConstantForWeightedAverageOfTemperature(0.41));
		assertFalse(Square.isValidConstantForWeightedAverageOfTemperature(0.09));
	}
	
	@Test
	public final void setConstantForWeightedAverageOfTemperature_legalCase() {
		Square.setConstantForWeightedAverageOfTemperature(0.2);
		assertEquals(0,Double.compare(0.2, Square.getConstantForWeightedAverageOfTemperature()));
	}

	@Test (expected=IllegalArgumentException.class)
	public final void setConstantForWeightedAverageOfTemperature_illegalCase() {
		Square.setConstantForWeightedAverageOfTemperature(0.5);
	}
	
	@Test
	public final void merge() {
		Square secondSquare = new Square();
		double squareOneBeforeTemperature = square.getTemperature(Temperature.CELCIUS);
		double squareTwoBeforeTemperature = secondSquare.getTemperature(Temperature.CELCIUS);
		double squareOneBeforeHumidity = square.getHumidity();
		double squareTwoBeforeHumidity = secondSquare.getHumidity();
		
		square.mergeWith(secondSquare, Direction.ONE);
		
		double expectedTemperatureAfterMerging = square.calculateWeightedAverage(
							squareOneBeforeTemperature, squareTwoBeforeTemperature);
		double expectedHumidityAfterMerging = square.calculateAverage(
							squareOneBeforeHumidity, squareTwoBeforeHumidity);
		
		
		assertEquals(0,Double.compare(expectedTemperatureAfterMerging,square.getTemperature(Temperature.CELCIUS)));
		assertEquals(0,Double.compare(expectedHumidityAfterMerging,square.getHumidity()));
		assertEquals(0,Double.compare(square.getTemperature(Temperature.CELCIUS), 
										secondSquare.getTemperature(Temperature.CELCIUS)));	
		assertEquals(0,Double.compare(square.getHumidity(), secondSquare.getHumidity()));
	}
	
	@Test
    public final void calculateAverage() {
            assertEquals(0,Double.compare(1.5, square.calculateAverage(1, 2)));
            assertEquals(0,Double.compare(2, square.calculateAverage(1,3)));
            assertEquals(0,Double.compare(9.25, square.calculateAverage(0,18.5)));
    }
    
    @Test
    public final void calculateWeightedAverage() {
            assertEquals(0,Double.compare(16.605,square.calculateWeightedAverage(11.25,20)));
    }
    
    @Test
    public final void calculateWeight() {
            double weightNumberOne = square.calculateWeight(11.25,15.625);
            double weightNumberTwo = square.calculateWeight(20,15.625);
            
            assertEquals(0,Double.compare(2,weightNumberOne+weightNumberTwo));
            assertEquals(0,Double.compare(0.776,weightNumberOne));
            assertEquals(0,Double.compare(1.224,weightNumberTwo));
    }	
}